#include <stdio.h>
#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <cstdlib>
#include <cstring>
#include "constants.hpp"
#include <dirent.h>
#include <errno.h>
#include <unistd.h>
#include <climits>
using namespace std;

unsigned int get_current_job() {
    DIR *dp;
    struct dirent *dirp;
    if((dp  = opendir("in")) == NULL) {
        fprintf(stderr,"Error: (%d) while opening 'in' directory.\n",errno);
        exit(1);
    }
	unsigned int res=UINT_MAX;
    while ((dirp = readdir(dp)) != NULL) {
		if (dirp->d_type!=DT_REG) continue;
        int cur=atoi(dirp->d_name);
        if (res<cur+1) res=cur+1;
    }
    if (res==UINT_MAX) 
		res=0;
    closedir(dp);
    return res;	
}

char *do_job(char *s, unsigned int current_job) {
	char inname[16],tmpname[16],outname[16];
	sprintf(inname,"in/%u",current_job);
	sprintf(tmpname,"in/t%u",current_job);
	sprintf(outname,"out/%u",current_job);
	FILE *in,*out;
	printf("Writing job %d\n",current_job);
	out=fopen(tmpname,"w");
	fputs(s,out);
	fclose(out);
	rename(tmpname,inname);
	printf("Waiting for job %d\n",current_job);	
	while ((in=fopen(outname,"r"))==NULL) {
		sleep(1);
	}
	printf("Job %d is found\n",current_job);
	char *ans=new char[MAXANSWER];
	fgets(ans,MAXANSWER-1,in);
	fclose(in);
	return ans;
}

void error(char *msg) {
	perror(msg);
	exit(1);
}

int main(int argc, char *argv[]) {
	unsigned int cur_job=get_current_job();
	printf("Current job is: %d\n",cur_job);
	int sockfd, newsockfd, portno, n;
	socklen_t clilen;
	char buffer[MAXQUERY];
	struct sockaddr_in serv_addr, cli_addr;
	sockfd = socket(AF_INET, SOCK_STREAM, 0);
	if (sockfd < 0)
		error("ERROR opening socket");
	bzero((char *) &serv_addr, sizeof(serv_addr));
	portno = atoi(argv[1]);
	serv_addr.sin_family = AF_INET;
	serv_addr.sin_port = htons(portno);
	serv_addr.sin_addr.s_addr = INADDR_ANY;
	if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) error("ERROR on binding");
	listen(sockfd,5);
	printf("Ready to accept connections\n");
	clilen = sizeof(cli_addr);
	while (1) {
		newsockfd = accept(sockfd,(struct sockaddr *) &cli_addr, &clilen);
		if (newsockfd < 0) error("ERROR on accept");
		printf("Connection accepted\n");
		int pid = fork();
		if (pid < 0) error("ERROR on fork");
		if (pid == 0) {
			close(sockfd);
			bzero(buffer,256);
			n = read(newsockfd,buffer,255);
			if (n < 0) error("ERROR reading from socket");
			printf("Query fetched: '%s'\n",buffer);
			char *ans=do_job(buffer,cur_job);
			printf("Answer:\n%s\n",ans);
			n = write(newsockfd,ans,strlen(ans));
			if (n < 0) error("ERROR writing to socket");
			exit(0);
			close(newsockfd);
		} else {close(newsockfd);cur_job++;}
	}
	return 0;
}
